cmake_minimum_required(VERSION 3.11 FATAL_ERROR)

# 定义项目名称和使用的语言。
project(recipe-22 LANGUAGES CXX)

# 设置C++标准为C++11。
set(CMAKE_CXX_STANDARD 11)
# 禁用C++编译器扩展（推荐，以确保代码的可移植性）。
set(CMAKE_CXX_EXTENSIONS OFF)
# 强制要求使用指定的C++标准。
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 针对Windows平台，如果需要导出符号，可以设置此选项。
# 这通常用于构建DLL时，确保所有公共符号都被导出。
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

# 1. 定义我们的库：sum_integers
# add_library命令用于创建静态或动态库。
add_library(sum_integers sum_integers.cpp)

# 2. 定义主应用程序可执行文件
# add_executable命令用于创建可执行文件。
add_executable(sum_up main.cpp)
# target_link_libraries命令用于将库链接到可执行文件或另一个库。
# sum_up 可执行文件需要链接 sum_integers 库。
target_link_libraries(sum_up sum_integers)

# 3. 启用/禁用单元测试的选项
# option命令用于定义一个用户可配置的选项，默认值为ON。
option(ENABLE_UNIT_TESTS "Enable unit tests" ON)
# message命令用于在CMake配置过程中输出信息。
message(STATUS "Unit tests enabled: ${ENABLE_UNIT_TESTS}")

# 只有当ENABLE_UNIT_TESTS为ON时，才执行后续与测试相关的CMake代码。
if(ENABLE_UNIT_TESTS)
    # 4. 引入FetchContent模块
    # FetchContent模块允许在配置时下载外部项目。
    include(FetchContent)

    # 5. 声明要获取的Google Test项目
    # FetchContent_Declare用于声明一个外部内容源。
    FetchContent_Declare(
        googletest # 外部项目的名称，后续会用到这个名称来引用它。
        GIT_REPOSITORY https://github.com/google/googletest.git # Git仓库URL。
        GIT_TAG release-1.8.0 # 指定要下载的Git标签或提交哈希，确保版本一致性。
        # GIT_SHALLOW TRUE # 可选：进行浅克隆，减少下载时间。
    )

    # 6. 查询Google Test项目是否已被填充
    # FetchContent_GetProperties用于获取已声明内容的属性，
    # 例如是否已被下载和配置（POPULATED）。
    FetchContent_GetProperties(googletest)

    # 7. 如果Google Test尚未被填充，则进行下载和配置
    if(NOT googletest_POPULATED)
        # FetchContent_Populate用于执行下载和解压操作。
        # 它会设置 ${googletest_SOURCE_DIR} 和 ${googletest_BINARY_DIR} 变量。
        FetchContent_Populate(googletest)

        # 针对Visual Studio的特定配置：
        # 强制Google Test使用共享运行时库（CRT），以避免与主项目不一致。
        set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
        # 禁用Google Test使用PThreads，避免潜在的冲突或不必要的依赖。
        set(gtest_disable_pthreads ON CACHE BOOL "" FORCE)

        # 将下载的Google Test项目添加为当前项目的一个子目录。
        # 这会处理Google Test自身的CMakeLists.txt，并使其内部定义的target可用。
        # 例如，它会定义 gtest, gtest_main, gmock, gmock_main 等目标。
        add_subdirectory(
            ${googletest_SOURCE_DIR} # Google Test的源代码目录。
            ${googletest_BINARY_DIR} # Google Test的构建目录。
        )

        # 针对MSVC编译器的特定警告处理：
        # 解决在MSVC下编译Google Test时可能出现的std::tr1命名空间弃用警告。
        if(MSVC)
            foreach(_tgt gtest gtest_main gmock gmock_main)
                target_compile_definitions(${_tgt}
                    PRIVATE
                        "_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING"
                )
            endforeach()
        endif()
    endif()

    # 8. 定义单元测试可执行文件
    # 创建一个名为 cpp_test 的可执行文件。
    add_executable(cpp_test "") # 初始为空，后续通过target_sources添加源文件。

    # 9. 指定测试可执行文件的源文件
    # target_sources命令用于向目标添加源文件。
    target_sources(cpp_test
        PRIVATE # PRIVATE表示这些源文件仅用于构建此目标，不影响其他目标。
            test.cpp # 我们的测试用例文件。
    )

    # 10. 链接测试可执行文件所需的库
    # cpp_test 需要链接 sum_integers 库（因为它测试这个库）
    # 还需要链接 gtest_main 库，这是Google Test提供的包含main函数的库。
    target_link_libraries(cpp_test
        PRIVATE
            sum_integers # 链接我们自己定义的库。
            gtest_main   # 链接Google Test的主库，它包含了测试运行器。
    )

    # 11. 启用并添加测试到CTest
    # enable_testing() 必须在 add_test() 之前调用，以启用CTest测试发现。
    enable_testing()
    # add_test命令用于向CTest注册一个测试。
    add_test(
        NAME google_test # 测试的名称，在ctest输出中显示。
        COMMAND $<TARGET_FILE:cpp_test> # 运行测试的命令，这里使用CMake生成的可执行文件路径。
    )
endif()